package com.mk.cloud.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mk.cloud.common.config.AppConfig;
import org.osgl.util.S;

import java.io.*;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.*;

/**
 * 快递物流查询工具类
 * Created by cb on 2016/12/14.
 */

public class KuaiDiUtils {
    private static Map<String, String> mapCompany;
    private static char[] base64EncodeChars = new char[]{
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
        'w', 'x', 'y', 'z', '0', '1', '2', '3',
        '4', '5', '6', '7', '8', '9', '+', '/'};

    static {
        mapCompany = new HashMap<String, String>();
        mapCompany.put("shentong", "STO");
        mapCompany.put("shunfeng", "SF");
        mapCompany.put("yuantong", "YTO");
        mapCompany.put("yunda", "YD");
        mapCompany.put("zhongtong", "ZTO");
        mapCompany.put("ems", "EMS");
    }

    /**
     * deliverystatus	物流状态 1在途中 2派件中 3已签收 4派送失败(拒签等)
     *
     * @param company 物流公司编码
     * @param number  物流单号
     * @return json
     */
    public static String getLogisticsInformation(String company, String number) {
        try {
            String juc = AppConfig.kdjs.usedcompany.get();
            List<String> js_used_company = null;
            if (S.isNotBlank(juc)) {
                js_used_company = Arrays.asList(juc.split(","));
            }

            if (js_used_company != null && js_used_company.contains(company)) {//极速
                //return KuaiDiUtils.getJiSu(company, number);
                String info = KuaiDiUtils.getKdiNiao(company, number);
                JSONObject objs = (JSONObject) JSON.parse(info);
                Map<String, Object> map = new HashMap<String, Object>();
                Map<String, Object> resultmap = new HashMap<String, Object>();
                for (Map.Entry<String, Object> entry : objs.entrySet()) {
                    if ("Success".equals(entry.getKey())) {
                        if ((Boolean) entry.getValue()) {
                            map.put("msg", "ok");
                            map.put("status", "0");
                        } else {
                            map.put("msg", objs.get("Reason"));
                            map.put("status", "1");
                        }
                    } else if ("LogisticCode".equals(entry.getKey())) {
                        resultmap.put("number", entry.getValue());
                    } else if ("ShipperCode".equals(entry.getKey())) {
                        resultmap.put("type", entry.getValue());
                    } else if ("State".equals(entry.getKey())) {
                        resultmap.put("deliverystatus", entry.getValue());
                    } else if ("Traces".equals(entry.getKey())) {
                        //data处理begin:context替换成status
                        JSONArray datas = (JSONArray) JSON.parseArray(entry.getValue().toString());
                        List<Map<String, Object>> new_list = new ArrayList<Map<String, Object>>();
                        for (Object data : datas) {
                            Map<String, Object> mapDatas = new HashMap<String, Object>();
                            for (Map.Entry<String, Object> d : ((Map<String, Object>) data).entrySet()) {
                                if ("AcceptStation".equals(d.getKey())) {
                                    mapDatas.put("status", d.getValue());
                                } else if ("AcceptTime".equals(d.getKey())) {
                                    mapDatas.put("time", d.getValue());
                                }
                            }
                            new_list.add(mapDatas);
                        }
                        new_list.sort(new FieldComparator(null, true));
                        //CollectionUtils.sort(new_list, true);
                        //data处理end-----------------------------------------
                        resultmap.put("list", new_list);
                    }

                    map.put("result", resultmap);
                }


                return JSON.toJSONString(map, false);
            } else {//快递100
                String info = KuaiDiUtils.getKuaiDi100(company, number);
                JSONObject objs = (JSONObject) JSON.parse(info);
                Map<String, Object> map = new HashMap<String, Object>();
                Map<String, Object> resultmap = new HashMap<String, Object>();
                for (Map.Entry<String, Object> entry : objs.entrySet()) {
                    if ("com".equals(entry.getKey())) {
                        resultmap.put("type", entry.getValue());
                    } else if ("nu".equals(entry.getKey())) {
                        resultmap.put("number", entry.getValue());
                    } else if ("message".equals(entry.getKey())) {
                        map.put("msg", entry.getValue());
                    } else if ("state".equals(entry.getKey())) {
                        //极速deliverystatus: 1在途中 2派件中 3已签收 4派送失败(拒签等)
                        //快递100state：0：在途      1：揽件  2：疑难 3：签收  4：退签  5：派件   6：退回
                        // 对应关系       1           2         4       3          4       2     4
                        if ("0".equals(entry.getValue())) {
                            resultmap.put("deliverystatus", "1");
                        } else if ("1".equals(entry.getValue())) {
                            resultmap.put("deliverystatus", "2");
                        } else if ("2".equals(entry.getValue())) {
                            resultmap.put("deliverystatus", "4");
                        } else if ("3".equals(entry.getValue())) {
                            resultmap.put("deliverystatus", "3");
                        } else if ("4".equals(entry.getValue())) {
                            resultmap.put("deliverystatus", "4");
                        } else if ("5".equals(entry.getValue())) {
                            resultmap.put("deliverystatus", "2");
                        } else if ("6".equals(entry.getValue())) {
                            resultmap.put("deliverystatus", "4");
                        }

                    } else if ("status".equals(entry.getKey())) {
                        if ("1".equals(entry.getValue())) {//状态码变成0为成功和极速一致
                            map.put("status", "0");
                        } else {
                            map.put("status", "1");
                        }
                    } else if ("data".equals(entry.getKey())) {
                        //data处理begin:context替换成status
                        JSONArray datas = (JSONArray) JSON.parseArray(entry.getValue().toString());
                        List<Map<String, Object>> new_list = new ArrayList<Map<String, Object>>();
                        for (Object data : datas) {
                            Map<String, Object> mapDatas = new HashMap<String, Object>();
                            for (Map.Entry<String, Object> d : ((Map<String, Object>) data).entrySet()) {
                                if ("context".equals(d.getKey())) {
                                    mapDatas.put("status", d.getValue());
                                } else if ("time".equals(d.getKey())) {
                                    mapDatas.put(d.getKey(), d.getValue());
                                }
                            }
                            new_list.add(mapDatas);
                        }
                        //data处理end-----------------------------------------
                        resultmap.put("list", new_list);
                    }
                    map.put("result", resultmap);
                    //System.out.println(entry.getKey()+"-"+entry.getValue()+"\t");
                }
                return JSON.toJSONString(map, false);
            }
        } catch (Exception e) {
            JSONObject json = new JSONObject();
            json.put("msg", "抱歉，暂时没有该单号的物流信息");
            json.put("result", new JSONObject());
            json.put("status", "205");
            return json.toJSONString();
        }


    }


    //极速快递

    //快递100
    private static String getKuaiDi100(String company, String number) {
        String api_url = AppConfig.kd100.url.get() + "?id=" + AppConfig.kd100.key.get() + "&com=" + company + "&nu=" + number + "&show=0&muti=1&order=desc";
        return HttpUtils.doGet(api_url);
    }

    /**
     * "kuaidi": {
     * "msg": "请求超过次数限制",
     * "result": "",
     * "status": "104"
     * 101	APPKEY为空或不存在
     * 102	APPKEY已过期
     * 103	APPKEY无请求此数据权限
     * 104	请求超过次数限制
     * 105	IP被禁止
     * 106	IP请求超过限制
     * 107	接口维护中
     * 108
     * <p>
     * 状态为104时,特殊处理result
     * }
     */
    private static String getJiSu(String company, String number) {
        String api_url = AppConfig.kdjs.url.get() + "?appkey=" + AppConfig.kdjs.key.get() + "&type=auto&number=" + number;
        String kuaidi = HttpUtils.doGet(api_url);
        JSONObject json = JSON.parseObject(kuaidi);
        if (json == null) {
            json = new JSONObject();
            json.put("result", new JSONObject());
            return json.toJSONString();
        }
        if (!S.eq(json.getString("status"), "0")) {
            json.put("result", new JSONObject());
        }
        return json.toJSONString();
    }

    //快递鸟快递
    private static String getKdiNiao(String company, String number) {
        try {
            String requestData = "{'OrderCode':'','ShipperCode':'" + mapCompany.get(company) + "','LogisticCode':'" + number + "'}";
            Map<String, String> params = new HashMap<String, String>();
            params.put("RequestData", URLEncoder.encode(requestData, "UTF-8"));
            params.put("EBusinessID", AppConfig.kdn.id.get());
            params.put("RequestType", "1002");
            String dataSign = encrypt(requestData, AppConfig.kdn.key.get(), "UTF-8");

            params.put("DataSign", URLEncoder.encode(dataSign, "UTF-8"));
            params.put("DataType", "2");
            return sendPost(AppConfig.kdn.url.get(), params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 电商Sign签名生成
     *
     * @param content  内容
     * @param keyValue Appkey
     * @param charset  编码方式
     * @return DataSign签名
     * @throws UnsupportedEncodingException ,Exception
     */
    private static String encrypt(String content, String keyValue, String charset) throws UnsupportedEncodingException, Exception {
        if (keyValue != null) {
            return base64(MD5(content + keyValue, charset), charset);
        }
        return base64(MD5(content, charset), charset);
    }

    /**
     * base64编码
     *
     * @param str     内容
     * @param charset 编码方式
     * @throws UnsupportedEncodingException
     */
    private static String base64(String str, String charset) throws UnsupportedEncodingException {
        String encoded = base64Encode(str.getBytes(charset));
        return encoded;
    }

    private static String MD5(String str, String charset) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(str.getBytes(charset));
        byte[] result = md.digest();
        StringBuffer sb = new StringBuffer(32);
        for (int i = 0; i < result.length; i++) {
            int val = result[i] & 0xff;
            if (val <= 0xf) {
                sb.append("0");
            }
            sb.append(Integer.toHexString(val));
        }
        return sb.toString().toLowerCase();
    }

    public static String base64Encode(byte[] data) {
        StringBuffer sb = new StringBuffer();
        int len = data.length;
        int i = 0;
        int b1, b2, b3;
        while (i < len) {
            b1 = data[i++] & 0xff;
            if (i == len) {
                sb.append(base64EncodeChars[b1 >>> 2]);
                sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
                sb.append("==");
                break;
            }
            b2 = data[i++] & 0xff;
            if (i == len) {
                sb.append(base64EncodeChars[b1 >>> 2]);
                sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
                sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
                sb.append("=");
                break;
            }
            b3 = data[i++] & 0xff;
            sb.append(base64EncodeChars[b1 >>> 2]);
            sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
            sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
            sb.append(base64EncodeChars[b3 & 0x3f]);
        }
        return sb.toString();
    }

    private static String sendPost(String url, Map<String, String> params) {
        OutputStreamWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try {
            URL realUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // POST方法
            conn.setRequestMethod("POST");
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.connect();
            // 获取URLConnection对象对应的输出流
            out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
            // 发送请求参数
            if (params != null) {
                StringBuilder param = new StringBuilder();
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    if (param.length() > 0) {
                        param.append("&");
                    }
                    param.append(entry.getKey());
                    param.append("=");
                    param.append(entry.getValue());
                    //System.out.println(entry.getKey()+":"+entry.getValue());
                }
                //System.out.println("param:"+param.toString());
                out.write(param.toString());
            }
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result.toString();
    }
    /**
     * 字段排序
     *
     * @author Jing.Zhuo
     */
    private static class FieldComparator implements Comparator<Object> {
        private final String field;
        private final boolean isDESC;
        private Method getMethodA;
        private Method getMethodB;

        FieldComparator(String field, boolean isDESC) {
            this.field = field;
            this.isDESC = isDESC;
        }

        @Override
        public int compare(Object a, Object b) {
            int rst = 0;
            try {
                rst = compareAsc(a, b);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return isDESC ? -rst : rst;
        }

        /**
         * 返回顺序对比结果
         *
         * @param a 排序对象
         * @param b 排序对象
         * @return
         * @throws Exception
         */
        int compareAsc(Object a, Object b) throws Exception {
            if (a == null && b == null) {
                return 0;
            }
            if (a == null) {
                return -1;
            }
            if (b == null) {
                return 1;
            }
            Object fieldA = null, fieldB = null;

            if (field != null) {
                if (a instanceof Map) {
                    fieldA = ((Map) a).get(field);
                } else {
                    if (getMethodA == null) {
                        getMethodA = BeanUtils.getMethod(field, a.getClass());
                    }
                    if (getMethodA != null)
                        fieldA = getMethodA.invoke(a);
                }

                if (b instanceof Map) {
                    fieldB = ((Map) b).get(field);
                } else {
                    if (getMethodB == null) {
                        getMethodB = BeanUtils.getMethod(field, b.getClass());
                    }
                    if (getMethodB != null)
                        fieldB = getMethodB.invoke(b);
                }
                if (fieldA == null && fieldB == null) {
                    return 0;
                }
                if (fieldA == null) {
                    return -1;
                }
                if (fieldB == null) {
                    return 1;
                }
            } else {
                fieldA = a;
                fieldB = b;
            }

            Class clz = fieldA.getClass();
            if (clz == Short.class || clz == short.class)
                return compareShort(fieldA, fieldB);
            if (clz == Integer.class || clz == int.class)
                return compareInteger(fieldA, fieldB);
            if (clz == Long.class || clz == long.class)
                return compareLong(fieldA, fieldB);
            if (clz == Float.class || clz == float.class)
                return compareFloat(fieldA, fieldB);
            if (clz == Double.class || clz == double.class)
                return compareDouble(fieldA, fieldB);
            if (clz == BigDecimal.class)
                return compareBigDecimal(fieldA, fieldB);
            if (clz == Date.class) {
                return compareDate(fieldA, fieldB);
            }
            return compareString(fieldA, fieldB);

        }

        private int compareString(Object fieldA, Object fieldB) {
            String strA = fieldA.toString();
            String strB = fieldB.toString();
            return strA.compareTo(strB);
        }

        private int compareShort(Object a, Object b) {
            return (Short) a - (Short) b;
        }

        private int compareInteger(Object a, Object b) {
            return (Integer) a - (Integer) b;
        }

        private int compareLong(Object a, Object b) {
            return (int) ((Long) a - (Long) b);
        }

        private int compareFloat(Object a, Object b) {
            return (int) ((Float) a - (Float) b);
        }

        private int compareDouble(Object a, Object b) {
            return (int) ((Double) a - (Double) b);
        }

        private int compareBigDecimal(Object a, Object b) {
            return ((BigDecimal) a).compareTo(((BigDecimal) b));
        }

        private int compareDate(Object a, Object b) {
            return ((Date) a).compareTo(((Date) b));
        }

        private String concatPinyinStringArray(String[] pinyinArray) {
            StringBuilder sb = new StringBuilder();
            if (pinyinArray != null && pinyinArray.length > 0) {
                for (String aPinyinArray : pinyinArray) {
                    sb.append(aPinyinArray);
                }
            }
            return sb.toString();
        }
    }

    public static void main(String[] args) {
//        String test = ;
//        System.out.println(getLogisticsInformation("wanxiangwuliu", "032479710474762-1"));
//        String test1 = getLogisticsInformation("shunfeng", "304580240545");
//        System.out.println(test1);
//        System.out.println(getLogisticsInformation("shentong", "400049792945"));
    }


}
